#include <asm-i386/io.h>
#include <asm-i386/irq.h>
-#include <xeno/sched.h> /* this has request_irq() proto for some reason */
+#include <xeno/sched.h>
#include <xeno/keyhandler.h>
#include <hypervisor-ifs/kbd.h>
#include <xeno/event.h>
+#include <xeno/console.h>
/* Hash-defines torn from <linux/pc_keyb.h> and <asm/keyboard.h> */
#define kbd_read_input() inb(KBD_DATA_REG)
#define kbd_read_status() inb(KBD_STATUS_REG)
-#define KEYBOARD_IRQ 1
+#define KEYBOARD_IRQ 1
+#define AUX_IRQ 12
+
#define kbd_write_output(val) outb(val, KBD_DATA_REG)
#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
-#define AUX_IRQ 12
-
-#undef KBD_DEBUG
-
-/* THIS SECTION DEALS WITH CONFIG_XEN_ATTENTION_KEY */
-
-// always set for now. potentially moved to a central config later.
-// this should really affect common/keyhandler.c too
-#define CONFIG_XEN_ATTENTION_KEY
-
#ifdef CONFIG_XEN_ATTENTION_KEY
static int xen_attention_key_down = 0;
-#define XEN_ATTENTION_KEY 0x46 // scroll lock
+#define XEN_ATTENTION_KEY 0x46 /* Scroll Lock */
#define KBD_SCANCODE_KEYUP_MASK 0x80
-/* naive scancode -> key mappings for internal xen use */
+/* Simple scancode-to-key mappings for internal Xen use. */
static unsigned char keymap_normal[] =
{
- 0 , 0 ,'1','2', '3','4','5','6', '7','8','9','0', '-','=','\b','\t',
- 'q','w','e','r', 't','y','u','i', 'o','p','[',']','\r', 0 ,'a','s',
- 'd','f','g','h', 'j','k','l',';', '\'','`', 0 ,'#', 'z','x','c','v',
- 'b','n','m',',', '.','/', 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
-
- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
- 0 , 0 , 0 , 0 , 0 , 0 ,'\\', 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
+ 0 , 0 ,'1','2', '3','4','5','6', '7','8','9','0', '-','=','\b','\t',
+ 'q','w','e','r', 't','y','u','i', 'o','p','[',']','\r', 0 ,'a','s',
+ 'd','f','g','h', 'j','k','l',';', '\'','`', 0 ,'#', 'z','x','c','v',
+ 'b','n','m',',', '.','/', 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 ,'\\', 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
};
static unsigned char keymap_shift[] =
{
- 0 , 0 ,'!','"', '#','$','%','^', '&','*','(',')', '_','+','\b','\t',
- 'Q','W','E','R', 'T','Y','U','I', 'O','P','{','}','\r', 0 ,'A','S',
- 'D','F','G','H', 'J','K','L',':', '@', 0 , 0 ,'~', 'Z','X','C','V',
- 'B','N','M','<', '>','?', 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
-
- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
- 0 , 0 , 0 , 0 , 0 , 0 ,'|', 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
-};
-
-
-static unsigned char keymap_control[] =
-{ /* same as normal, except for a-z -> 1 to 26 */
- 0 , 0 ,'1','2', '3','4','5','6', '7','8','9','0', '-','=','\b','\t',
- 17, 23, 5 , 18, 20, 25, 21, 9 , 15, 16,'[',']','\r', 0 , 1 , 19,
- 4 , 6 , 7 , 8 , 10, 11, 12,';', '\'','`', 0 ,'#', 26, 24, 3 , 22,
- 2 , 14, 13,',', '.','/', 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
-
- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
- 0 , 0 , 0 , 0 , 0 , 0 ,'\\', 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
+ 0 , 0 ,'!','"', '#','$','%','^', '&','*','(',')', '_','+','\b','\t',
+ 'Q','W','E','R', 'T','Y','U','I', 'O','P','{','}','\r', 0 ,'A','S',
+ 'D','F','G','H', 'J','K','L',':', '@', 0 , 0 ,'~', 'Z','X','C','V',
+ 'B','N','M','<', '>','?', 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 ,'|', 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
};
static int keyboard_shift = 0;
-static int keyboard_control = 0;
-static int keyboard_echo = 0;
static unsigned char convert_scancode (unsigned char scancode)
{
unsigned char value = 0;
- switch (scancode) {
-
- case 0xbb: /* F1 */
- keyboard_echo = !keyboard_echo;
- break;
-
- case 0xba: /* caps lock UP */
- case 0x9d: /* ctrl (left) UP */
- keyboard_control = 0;
- break;
-
- case 0x3a: /* caps lock DOWN */
- case 0x1d: /* ctrl (left) DOWN */
- keyboard_control = 1;
- break;
+ switch ( scancode )
+ {
case 0xaa: /* shift (left) UP */
case 0xb6: /* shift (right) UP */
keyboard_shift = 1;
break;
- default: /* normal keys */
- // dont process key-down events
- if(!(scancode & KBD_SCANCODE_KEYUP_MASK)) break;
-
- scancode = scancode & (~KBD_SCANCODE_KEYUP_MASK);
- if (keyboard_control)
- value = keymap_control[scancode];
- else if (keyboard_shift)
+ default:
+ /* Only process key-up events */
+ if(!(scancode & KBD_SCANCODE_KEYUP_MASK))
+ break;
+ scancode = scancode & ~KBD_SCANCODE_KEYUP_MASK;
+ if (keyboard_shift)
value = keymap_shift[scancode];
else
value = keymap_normal[scancode];
-
+ break;
}
- if (value && keyboard_echo) printk ("%c", value);
-
return value;
}
#endif /* CONFIG_XEN_ATTENTION_KEY */
-/* THIS SECTION DEALS WITH STORING A RING OF PENDING KBD EVENTS */
-
-// store kbd events waiting to be processed by guest os
-#define KBD_RING_SIZE 64
+/* We store kbd events awaiting receive by a guest OS in a ring buffer. */
+#define KBD_RING_SIZE 64
static int kbd_ring[KBD_RING_SIZE];
static int kbd_ring_prod = 0;
static int kbd_ring_cons = 0;
-#define KBD_RING_INC(_i) (((_i)+1) & (KBD_RING_SIZE-1))
-#define KBD_RING_FULL (KBD_RING_INC(kbd_ring_prod) == kbd_ring_cons)
-#define KBD_RING_EMPTY (kbd_ring_prod == kbd_ring_cons)
-
-// these assume locking has already been taken care of
-static void kbd_ring_push(unsigned char status, unsigned char scancode) {
- if(KBD_RING_FULL) return;
- kbd_ring[kbd_ring_prod] = KBD_CODE(scancode, status);
- kbd_ring_prod = KBD_RING_INC(kbd_ring_prod);
-}
+#define KBD_RING_INC(_i) (((_i)+1) & (KBD_RING_SIZE-1))
+#define KBD_RING_FULL (KBD_RING_INC(kbd_ring_prod) == kbd_ring_cons)
+#define KBD_RING_EMPTY (kbd_ring_prod == kbd_ring_cons)
-static int kbd_ring_pop() {
- int ret;
- if(KBD_RING_EMPTY) {
- // read directly from controller - no events waiting in ring
- unsigned char status = kbd_read_status();
- unsigned char scancode = kbd_read_input();
- return KBD_CODE(scancode, status);
- }
- ret = kbd_ring[kbd_ring_cons];
- kbd_ring_cons = KBD_RING_INC(kbd_ring_cons);
- return ret;
+static void kbd_ring_push(unsigned char status, unsigned char scancode)
+{
+ if ( KBD_RING_FULL )
+ return;
+
+ kbd_ring[kbd_ring_prod] = KBD_CODE(scancode, status);
+ kbd_ring_prod = KBD_RING_INC(kbd_ring_prod);
}
+static int kbd_ring_pop(void)
+{
+ int ret;
+
+ if ( KBD_RING_EMPTY )
+ {
+ /* Read directly from controller - no events waiting in ring. */
+ unsigned char status = kbd_read_status();
+ unsigned char scancode = kbd_read_input();
+ ret = KBD_CODE(scancode, status);
+ }
+ else
+ {
+ ret = kbd_ring[kbd_ring_cons];
+ kbd_ring_cons = KBD_RING_INC(kbd_ring_cons);
+ }
-/* THIS SECTION DEALS WITH COMMUNICATING PS2 EVENTS/CMDS WITH GUEST OS */
+ return ret;
+}
-#include <xeno/console.h>
-// need lock as there may be _two_ interrupts at play, keyboard and mouse, as well as guest os actions
+/*
+ * NB. Lock is essential as there are two distinct interrupts (keyboard + aux).
+ * Also interrupts may disturb guest OS actions.
+ */
static spinlock_t kbd_lock;
-
long do_kbd_op(unsigned char op, unsigned char val)
{
- // check for domain 0
-#ifdef KBD_DEBUG
- printk("do_kbd_op: op %2x, val %2x, prod %d, cons %d\n", op, val, kbd_ring_prod, kbd_ring_cons);
-#endif
+ unsigned long flags;
+ long ret = -EINVAL;
- if ( !CONSOLE_ISOWNER(current) ) return -EPERM;
+ if ( !CONSOLE_ISOWNER(current) )
+ return -EPERM;
- switch(op) {
- case KBD_OP_WRITEOUTPUT:
- kbd_write_output(val);
- return 0L;
- case KBD_OP_WRITECOMMAND:
- kbd_write_command(val);
- return 0L;
- case KBD_OP_READ: {
- unsigned long flags;
- unsigned long ret;
spin_lock_irqsave(&kbd_lock, flags);
- ret = kbd_ring_pop();
+
+ switch ( op )
+ {
+ case KBD_OP_WRITEOUTPUT:
+ kbd_write_output(val);
+ ret = 0L;
+ break;
+ case KBD_OP_WRITECOMMAND:
+ kbd_write_command(val);
+ ret = 0L;
+ break;
+ case KBD_OP_READ:
+ ret = kbd_ring_pop();
+ break;
+ }
+
spin_unlock_irqrestore(&kbd_lock, flags);
- return ret;
- }
- }
- return -EINVAL;
+ return ret;
}
static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- unsigned char status;
- unsigned int work = 1000;
- unsigned long cpu_mask;
- unsigned long flags;
- spin_lock_irqsave(&kbd_lock, flags);
- status = kbd_read_status();
-
-#ifdef KBD_DEBUG
- printk("keyboard_interrupt irq %d, status 0x%2x\n", irq, status);
-#endif
- while ((--work > 0) && (status & KBD_STAT_OBF))
+ unsigned char status, scancode;
+ unsigned int work = 1000;
+ unsigned long cpu_mask, flags;
+
+ spin_lock_irqsave(&kbd_lock, flags);
+
+ while ( (--work > 0) && ((status = kbd_read_status()) & KBD_STAT_OBF) )
{
- unsigned char scancode;
- scancode = kbd_read_input();
- //printk("scancode 0x%2x\n", scancode);
+ scancode = kbd_read_input();
#ifdef CONFIG_XEN_ATTENTION_KEY
- if(!(status & (KBD_STAT_GTO | KBD_STAT_PERR | KBD_STAT_MOUSE_OBF))) {
- if ((scancode & (~KBD_SCANCODE_KEYUP_MASK)) == XEN_ATTENTION_KEY) {
- xen_attention_key_down = !(scancode & KBD_SCANCODE_KEYUP_MASK);
- //printk("xen_attention_key_down %d\n", xen_attention_key_down);
- } else if (xen_attention_key_down) {
- key_handler *handler;
- unsigned char key;
-
- spin_unlock_irqrestore(&kbd_lock, flags);
- key = convert_scancode(scancode);
- if(key && (handler = get_key_handler(key)))
- (*handler)(key, dev_id, regs);
-
- spin_lock_irqsave(&kbd_lock, flags);
- status = kbd_read_status();
- continue; // do not send key to guest os
- }
- }
+ if ( !(status & (KBD_STAT_GTO | KBD_STAT_PERR | KBD_STAT_MOUSE_OBF)) )
+ {
+ if ( (scancode & (~KBD_SCANCODE_KEYUP_MASK)) == XEN_ATTENTION_KEY )
+ {
+ xen_attention_key_down = !(scancode & KBD_SCANCODE_KEYUP_MASK);
+ }
+ else if ( xen_attention_key_down )
+ {
+ key_handler *handler;
+ unsigned char key;
+ spin_unlock_irqrestore(&kbd_lock, flags);
+ key = convert_scancode(scancode);
+ if ( key && (handler = get_key_handler(key)) )
+ (*handler)(key, dev_id, regs);
+ spin_lock_irqsave(&kbd_lock, flags);
+ continue;
+ }
+ }
#endif
- if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR))) {
- kbd_ring_push(status, scancode);
-
- cpu_mask = mark_guest_event(CONSOLE_OWNER, _EVENT_KBD);
+ kbd_ring_push(status, scancode);
+ cpu_mask = mark_guest_event(CONSOLE_OWNER, _EVENT_KBD);
guest_event_notify(cpu_mask);
-
- status = kbd_read_status();
- //scancode = kbd_read_input();
- }
}
- if (!work)
- printk(KERN_ERR "xen_keyb: controller jammed (0x%02X).\n", status);
+ if ( !work )
+ printk(KERN_ERR "xen_keyb: controller jammed (0x%02X).\n", status);
spin_unlock_irqrestore(&kbd_lock, flags);
}
void initialize_keyboard()
{
- spin_lock_init(&kbd_lock);
-
- if(request_irq(KEYBOARD_IRQ, keyboard_interrupt, SA_NOPROFILE, "keyboard", NULL)) {
- printk("initialize_keyboard: failed to alloc IRQ %d\n", KEYBOARD_IRQ);
- return;
- }
+ spin_lock_init(&kbd_lock);
- if(request_irq(AUX_IRQ, keyboard_interrupt, SA_NOPROFILE, "PS/2 Mouse", NULL)) {
- printk("initialize_keyboard: failed to alloc IRQ %d\n", AUX_IRQ);
- return;
- }
+ if( request_irq(KEYBOARD_IRQ, keyboard_interrupt,
+ SA_NOPROFILE, "keyboard", NULL))
+ {
+ printk("initialize_keyboard: failed to alloc IRQ %d\n", KEYBOARD_IRQ);
+ return;
+ }
-#ifdef KBD_DEBUG
- printk("PS/2 keyboard and mouse interface ok");
-#endif
+ if ( request_irq(AUX_IRQ, keyboard_interrupt,
+ SA_NOPROFILE, "PS/2 Mouse", NULL))
+ {
+ printk("initialize_keyboard: failed to alloc IRQ %d\n", AUX_IRQ);
+ return;
+ }
}